home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1995 April / Internet Tools.iso / infoserv / www / cern / dev / www-talk.9301-9306.Z / www-talk.9301-9306 / text0576.txt < prev    next >
Encoding:
Text File  |  1995-04-24  |  6.5 KB  |  229 lines

  1.  
  2. I sent this to tim a while ago, but I don't think
  3. he's had time to look at it.
  4.  
  5. Meanwhile, libWWW is becomming reentrant, but I still
  6. think the architecture is kinda clumsy: you have to
  7. have a big data structure describing the DTD, and
  8. a routine for each element, etc.
  9.  
  10. This doesn't mesh well with the MidasWWW architecture, which
  11. can read the DTD from the X resource database at
  12. runtime.
  13.  
  14. I have an idea for an architecture that the linemode and
  15. MidasWWW could share (along with other new implementations).
  16.  
  17. It's not radically different from the current libWWW, but
  18. there's a lot of grunt-work between the current libWWW
  19. and what I've got here. But I think the end result would
  20. be much more usable.
  21.  
  22. We start with the HText class. In stead of the various
  23. style and append methods, we have four methods in a
  24. virtual function table:
  25.  
  26. typedef struct{
  27.   int (*start_tag) PARAMS((SGML_Object this, CONST char* gi,
  28.                 CONST char** attributes, int nattrs));
  29.   VOID (*end_tag) PARAMS((SGML_Object this, CONST char* gi));
  30.  
  31.   VOID (*entity) PARAMS((SGML_Object this, CONST char* name));
  32.  
  33.   VOID (*data) PARAMS((SGML_Object this, CONST char* data, int char_qty));
  34. }SGML_DocClass;
  35.  
  36. The linemode would declare something like:
  37.  
  38. SGML_DocClass griddoc = {HText_start_tag, HText_end_tag,
  39.             HText_entity, HText_data};
  40.  
  41. The HText implementation is responsible for keeping track of
  42. the stack of open elements, if it needs to.
  43.  
  44. On top of these we build some format parsing routines:
  45.  
  46. SGML_parse(void* dest, void* closure, void* stream, int (getc)(void*));
  47. /* psuedocode:
  48.    int read, content;
  49.    char buffer[1000];
  50.    SGML_DocClass *docclass = (SGML_DocClass*)closure;
  51.  
  52.    while( (read = SGML_read(buffer, content, stream, getc)) != EOF){
  53.      switch(read){
  54.        case SGML_start_tag:
  55.          ... parse name, attributes ...
  56.          content = (docclass->startTag)(dest, name, attrs);
  57.          if(content = empty){
  58.            (docclass->endTag)(name);
  59.            content = MIXED; /*@@ could be ELEMENT */
  60.          }
  61.          break;
  62.  
  63.        case SGML_end_tag:
  64.          ... parse name ...
  65.          (docclass->endTag)(name);
  66.          content = MIXED; /*@@ could be ELEMENT */
  67.          break;
  68.  
  69.        case SGML_entity:
  70.          (docclass->entity)(data, name);
  71.          break;
  72.  
  73.        default:
  74.          (docclass->data)(dest, buffer);
  75.     }
  76. */
  77.  
  78. PlainText_parse(HText* dest, void* docclass, void* stream, int (getc)(void*));
  79. /* psuedocode:
  80.    (docclass->startTag)(dest, "HTML");
  81.    (docclass->startTag)(dest, "BODY");
  82.    (docclass->startTag)(dest, "PRE");
  83.    keep a local buffer of about 1000 chars.
  84.    Call (getc)(stream) until EOF.
  85.    Call HText_data(dest, buffer) whenever buffer is full.
  86.    (docclass->endTag)(dest, "PRE");
  87.    (docclass->endTag)(dest, "BODY");
  88.    (docclass->endTag)(dest, "HTML");
  89. */
  90.  
  91. GopherListing_parse(HText* dest, void* dummy, void* stream, int (getc)(void*));
  92. /* psuedocode:
  93.    (docclass->startTag)(dest, "HTML");
  94.    (docclass->startTag)(dest, "BODY");
  95.    (docclass->startTag)(dest, "MENU");
  96.    while(Gopher_parse_line(stream, getc, type, name, host, port, path)){
  97.       char addr[BIG];
  98.       sprintf(addr, "gopher://%s:%d/%c%s", host, port, type, path);
  99.       (docclass->startTag)(dest, "A",
  100.                        "HREF", addr,
  101.                        0);
  102.       (docclass->data)(dest, name);
  103.       (docclass->endTag)(dest, "A");
  104.    }
  105.    (docclass->endTag)(dest, "MENU");
  106.    (docclass->endTag)(dest, "BODY");
  107.    (docclass->endTag)(dest, "HTML"); 
  108. */
  109.  
  110.  
  111. We register each of these with the following routine:
  112.  
  113. int
  114. ContentType_register(CONST char* type, CONST char* subtype,
  115.         HTParseProc parse, void* closure);
  116.  
  117. For example:
  118.  
  119. main()
  120. {
  121.   ContentType_register("TEXT", "X-HTML", HTML_parse, griddoc);
  122.   ContentType_register("TEXT", "PLAIN", PlainText_parse, griddoc);
  123.   ContentType_register("APPLICATION", "X-GOPHER",
  124.              GopherListing_parse, griddoc);
  125. }
  126.  
  127.  
  128. The following routine can be used for any MIME entity. It will dispatch
  129. the appropriate parsing routine based on the content type header:
  130.  
  131. int
  132. ContentType_parse(const char* ct, HText* dest, void* stream, int (getc)(void*));
  133.  
  134.  
  135. Then we build some load routines, one per access scheme:
  136. (note that this design separates format from the access scheme, which
  137. allows us to, for example, load a gopher menu
  138. from a local file, or load HTML text from a Gopher server)
  139.  
  140. /* I don't have error handling worked out yet. We need to have a coherent
  141.    design for this. It's a mess in the current WWWlib. */
  142.  
  143. /* I think the WWW file: should be split into ftp: and local-file:.
  144.    It's cleaner to implement; there are precedents in the MidasWWW local:
  145.    scheme and the MIME ftp and local-file access-types. */
  146.  
  147. int
  148. LocalFile_load(HText* dest, CONST char* path, CONST char* search)
  149. {
  150.   FILE* stream;
  151.  
  152.   if(stream = fopen(path)){
  153.     const char* content_type = WWW_zen_content_type_from_extension(path);
  154.     ContentType_parse(content_type, dest, (void*)stream, (int ()(void*))getc);
  155.     fclose(stream);
  156.     return 1;
  157.   }else{
  158.     /* log an error */
  159.     return 0;
  160.   }
  161. }
  162.  
  163. int
  164. FTP_load(HText* dest, CONST char* path, CONST char* search);
  165.  
  166. int
  167. HTTP_load(HText* dest, CONST char* path, CONST char* search);
  168.  
  169. int
  170. Gopher_load(HText* dest, CONST char* path, CONST char* search);
  171. {
  172.   const char* content_type = Gopher_zen_content_type_from_gtype_char(*path);
  173.   char* host = HTParse(path, PARSE_HOST);
  174.   char* portnum = HTParse(path, PARSE_PORT);
  175.   int port = atoi(portnum);
  176.   static char* tab = "\007";
  177.   static char* crlf = "\015\012";
  178.  
  179.   void* stream = TCPOpen(host, port);
  180.  
  181.   if(stream){
  182.     TCPwrite(stream, path, strlen(path);
  183.     if(search){
  184.       TCPwrite(stream, tab, 1);
  185.       TCPwrite(stream, search, strlen(search);
  186.     }
  187.     TCPwrite(stream, crlf, 2);
  188.     ContentType_parse(content_type, dest, stream, TCPgetc);
  189.     TCPclose(stream);
  190.     return 1;
  191.    }else{
  192.     /* log an error */
  193.     return 0;
  194.    }
  195. }
  196.  
  197.  
  198. Then we register these just like formats:
  199.  
  200. HTAccess_register(const char* name, HTLoadProc load, void* closure);
  201.  
  202.  
  203. And the HTLoadDocument routine in HTAccess.c becomes this:
  204.  
  205. int
  206. HTAccess_load(HText* dest, HTParentAnchor* p, CONST char* address)
  207. {
  208.   char* scheme = HTParse(address, PARSE_SCHEME);
  209.   /* path is everything after the colon, except the anchor */
  210.   char* path = HTParse(address, PARSE_HOST|PARSE_PORT|PARSE_PATH);
  211.   char* anchor = HTParse(address, PARSE_ANCHOR);
  212.   char* search = HTParse(address, PARSE_SEARCH_TERMS);
  213.   HText dest = HText_new(p); /* check for doc already loaded in p @@ */
  214.   void* closure;
  215.   HTLoadProc load;
  216.  
  217.   if(load = /* load routine registered for scheme. find closure too */){
  218.     (load)(dest, path, search, closure);
  219.   }
  220.   HTSelect(dest, anchor);
  221. }
  222.  
  223.  
  224. What do you think?
  225.  
  226. Dan
  227.  
  228.  
  229.